home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programming Languages Suite
/
ProgLangD.iso
/
BORLAND TURBO
/
DROPEXT.PAK
/
DROPEXT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1997-05-05
|
18KB
|
617 lines
/******************************************************************************\
* This is a part of the Microsoft Source Code Samples.
* Copyright (C) 1994-1995 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
\******************************************************************************/
//---------------------------------------------------------------------------
//
// File: dropext.c
//
// This file contains a sample source code of context menu extension handler.
//
//---------------------------------------------------------------------------
#include "priv.h"
//
// Initialize GUIDs (should be done only and at-least once per DLL/EXE)
//
#pragma data_seg(".text")
#define INITGUID
#include <initguid.h>
#include "dropext.h"
#pragma data_seg()
//
// Function prototypes
//
HRESULT CALLBACK DropExt_CreateInstance(LPUNKNOWN, REFIID, LPVOID FAR*);
//
// Global variables
//
UINT g_cRefThisDll = 0; // Reference count of this DLL.
UINT g_cfNetResource = 0; // Clipboard format
//---------------------------------------------------------------------------
// LibMain
//---------------------------------------------------------------------------
#pragma argsused
BOOL APIENTRY LibMain(HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
{
switch(dwReason)
{
case DLL_PROCESS_ATTACH:
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_THREAD_ATTACH:
default:
break;
} // end switch()
return TRUE;
}
//---------------------------------------------------------------------------
// DllCanUnloadNow
//---------------------------------------------------------------------------
STDAPI DllCanUnloadNow(void)
{
return ResultFromScode((g_cRefThisDll==0) ? S_OK : S_FALSE);
}
//---------------------------------------------------------------------------
//
// DllGetClassObject
//
// This is the entry of this DLL, which all the In-Proc server DLLs should
// export. See the description of "DllGetClassObject" of OLE 2.0 reference
// manual for detail.
//
//---------------------------------------------------------------------------
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID FAR* ppvOut)
{
//
// This DLL has only one class (CLSID_SampleDropExt). If a DLL supports
// multiple classes, it should have either multiple if-statements or
// efficient table lookup code.
//
if (IsEqualIID(rclsid, &CLSID_SampleDropExt))
{
//
// We are supposed return the class object for this class. Instead
// of fully implementing it in this DLL, we just call a helper
// function in the shell DLL which creates a default class factory
// object for us. When its CreateInstance member is called, it
// will call back our create instance function (DropExt_CreateInstance).
//
return SHCreateDefClassObject(
riid, //
ppvOut, //
DropExt_CreateInstance, // callback function
&g_cRefThisDll, // reference count of this DLL
&IID_IShellExtInit // init interface
);
}
return ResultFromScode(E_FAIL);
}
//---------------------------------------------------------------------------
//
// CSampleDropExt class
//
// In C++:
// class CSampleDropExt : protected IContextMenu, protected IShellExtInit
// {
// protected:
// UINT _cRef;
// LPDATAOBJECT _pdtobj;
// HKEY _hkeyProgID;
// public:
// CSampleDropExt() _cRef(1), _pdtobj(NULL), _hkeyProgID(NULL) {};
// ...
// };
//
//---------------------------------------------------------------------------
typedef struct _CSampleDropExt // smx
{
IContextMenu _ctm; // 1st base class
IShellExtInit _sxi; // 2nd base class
UINT _cRef; // reference count
LPDATAOBJECT _pdtobj; // data object
HKEY _hkeyProgID; // reg. database key to ProgID
char _szTargetFolder[MAX_PATH];
} CSampleDropExt, * PSAMPLEDROPEXT;
#define SMX_OFFSETOF(x) ((UINT)(&((PSAMPLEDROPEXT)0)->x))
#define PVOID2PSMX(pv,offset) ((PSAMPLEDROPEXT)(((LPBYTE)pv)-offset))
#define PCTM2PSMX(pctm) PVOID2PSMX(pctm, SMX_OFFSETOF(_ctm))
#define PSXI2PSMX(psxi) PVOID2PSMX(psxi, SMX_OFFSETOF(_sxi))
//
// Vtable prototype
//
extern IContextMenuVtbl c_SampleDropExt_CTMVtbl;
extern IShellExtInitVtbl c_SampleDropExt_SXIVtbl;
//---------------------------------------------------------------------------
//
// DropExt_CreateInstance
//
// This function is called back from within IClassFactory::CreateInstance()
// of the default class factory object, which is created by SHCreateClassObject.
//
//---------------------------------------------------------------------------
HRESULT CALLBACK DropExt_CreateInstance(LPUNKNOWN punkOuter,
REFIID riid, LPVOID FAR* ppvOut)
{
HRESULT hres;
PSAMPLEDROPEXT psmx;
//
// Shell extentions typically does not support aggregation.
//
if (punkOuter) {
return ResultFromScode(CLASS_E_NOAGGREGATION);
}
//
// in C++:
// psmx = new CSampleDropExt();
//
psmx = LocalAlloc(LPTR, sizeof(CSampleDropExt));
if (!psmx) {
return ResultFromScode(E_OUTOFMEMORY);
}
psmx->_ctm.lpVtbl = &c_SampleDropExt_CTMVtbl;
psmx->_sxi.lpVtbl = &c_SampleDropExt_SXIVtbl;
psmx->_cRef = 1;
psmx->_pdtobj = NULL;
psmx->_hkeyProgID = NULL;
g_cRefThisDll++;
//
// in C++:
// hres = psmx->QueryInterface(riid, ppvOut);
// psmx->Release();
//
// Note that the Release member will free the object, if QueryInterface
// failed.
//
hres = c_SampleDropExt_CTMVtbl.QueryInterface(&psmx->_ctm, riid, ppvOut);
c_SampleDropExt_CTMVtbl.Release(&psmx->_ctm);
return hres; // S_OK or E_NOINTERFACE
}
//---------------------------------------------------------------------------
// CSampleDropExt::Initialize (IShellExtInit override)
//---------------------------------------------------------------------------
STDMETHODIMP DropExt_Initialize(LPSHELLEXTINIT psxi,
LPCITEMIDLIST pidlFolder,
LPDATAOBJECT pdtobj,
HKEY hkeyProgID)
{
PSAMPLEDROPEXT this = PSXI2PSMX(psxi);
// Initialize can be called more than once.
if (this->_pdtobj) {
this->_pdtobj->lpVtbl->Release(this->_pdtobj);
}
if (this->_hkeyProgID) {
RegCloseKey(this->_hkeyProgID);
}
// Duplicate the pdtobj pointer
if (pdtobj) {
this->_pdtobj = pdtobj;
pdtobj->lpVtbl->AddRef(pdtobj);
}
// Duplicate the handle
if (hkeyProgID) {
RegOpenKeyEx(hkeyProgID, NULL, 0L, MAXIMUM_ALLOWED, &this->_hkeyProgID);
}
// Get the path to the drop target folder
if (pidlFolder) {
SHGetPathFromIDList(pidlFolder, this->_szTargetFolder);
}
return NOERROR;
}
#pragma argsused
STDMETHODIMP DropExt_QueryContextMenu(LPCONTEXTMENU pctm,
HMENU hmenu,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags)
{
UINT idCmd = idCmdFirst;
InsertMenu(hmenu, indexMenu++, MF_STRING|MF_BYPOSITION, idCmd++, "Check H&DROP (dropext)");
InsertMenu(hmenu, indexMenu++, MF_STRING|MF_BYPOSITION, idCmd++, "Check H&NRES (dropext)");
return ResultFromScode(MAKE_SCODE(SEVERITY_SUCCESS, FACILITY_NULL, (USHORT)2));
}
//
// Converts an offset to a string to a string pointer.
//
LPCSTR _Offset2Ptr(LPSTR pszBase, UINT offset, UINT * pcb)
{
LPSTR pszRet;
if (offset==0) {
pszRet = NULL;
*pcb = 0;
} else {
pszRet = pszBase + offset;
*pcb = lstrlen(pszRet) + 1;
}
return pszRet;
}
//
// This is a helper routine which extracts a specified NETRESOURCE from hnres.
//
UINT DropExt_GetNetResource(HGLOBAL hnres, UINT iItem, LPNETRESOURCE pnresOut, UINT cbMax)
{
LPNRESARRAY panr = GlobalLock(hnres);
UINT iRet = 0; // assume error
if (hnres)
{
if (iItem==(UINT)-1)
{
iRet = panr->cItems;
}
else if (iItem < panr->cItems)
{
UINT cbProvider, cbRemoteName;
LPCSTR pszProvider = _Offset2Ptr((LPSTR)panr, (UINT)panr->nr[iItem].lpProvider, &cbProvider);
LPCSTR pszRemoteName = _Offset2Ptr((LPSTR)panr, (UINT)panr->nr[iItem].lpRemoteName, &cbRemoteName);
iRet = sizeof(NETRESOURCE) + cbProvider + cbRemoteName;
if (iRet <= cbMax)
{
LPSTR psz = (LPSTR)(pnresOut+1);
*pnresOut = panr->nr[iItem];
if (pnresOut->lpProvider) {
pnresOut->lpProvider = psz;
lstrcpy(psz, pszProvider);
psz += cbProvider;
}
if (pnresOut->lpRemoteName) {
pnresOut->lpRemoteName = psz;
lstrcpy(psz, pszRemoteName);
}
}
}
GlobalUnlock(hnres);
}
return iRet;
}
HRESULT DropExt_CheckForHDROP(PSAMPLEDROPEXT this, HWND hwnd)
{
FORMATETC fmte = {
CF_HDROP,
(DVTARGETDEVICE FAR *)NULL,
DVASPECT_CONTENT,
-1,
TYMED_HGLOBAL };
STGMEDIUM medium;
HRESULT hres = this->_pdtobj->lpVtbl->GetData(this->_pdtobj, &fmte, &medium);
if (SUCCEEDED(hres))
{
// STGMEDIUM uses anonymous unions, which are not supported in C.
// The code below is conditionalized to show you how the usage differs
// between C and C++.
#if defined (__cplusplus)
HDROP hdrop = medium.hGlobal;
#else
HDROP hdrop = medium.u.hGlobal;
#endif
UINT cFiles = DragQueryFile(hdrop, (UINT)-1, NULL, 0);
char szFile[MAX_PATH];
char szBuf[MAX_PATH*2+64];
DragQueryFile(hdrop, 0, szFile, sizeof(szFile));
wsprintf(szBuf,
"The drop target is %s.\n"
"%d files/directories in HDROP\n"
"The path to the first object is\n"
"\t%s.",
this->_szTargetFolder,
cFiles,
szFile);
MessageBox(hwnd, szBuf, "DropExt", MB_OK);
//
// HACK: We are supposed to call ReleaseStgMedium. This is a temporary
// hack until OLE 2.01 for Windows 95 is released.
//
if (medium.pUnkForRelease)
{
medium.pUnkForRelease->lpVtbl->Release(medium.pUnkForRelease);
}
else
{
// STGMEDIUM uses anonymous unions, which are not supported in C.
// The code below is conditionalized to show you how the usage differs
// between C and C++.
#if defined (__cplusplus)
GlobalFree(medium.hGlobal);
#else
GlobalFree(medium.u.hGlobal);
#endif
}
}
else
{
MessageBox(hwnd, "No file system object in the selection", "DropExt", MB_OK);
}
return hres;
}
HRESULT DropExt_CheckForHNRES(PSAMPLEDROPEXT this, HWND hwnd)
{
FORMATETC fmte;
STGMEDIUM medium;
HRESULT hres;
fmte.cfFormat = (CLIPFORMAT) (g_cfNetResource ? g_cfNetResource
: (g_cfNetResource = RegisterClipboardFormat("Net Resource")));
fmte.ptd = (DVTARGETDEVICE FAR *)NULL;
fmte.dwAspect = DVASPECT_CONTENT;
fmte.lindex = -1;
fmte.tymed = TYMED_HGLOBAL;
hres = this->_pdtobj->lpVtbl->GetData(this->_pdtobj, &fmte, &medium);
if (SUCCEEDED(hres))
{
// STGMEDIUM uses anonymous unions, which are not supported in C.
// The code below is conditionalized to show you how the usage differs
// between C and C++.
#if defined (__cplusplus)
HDROP hnres = medium.hGlobal;
#else
HDROP hnres = medium.u.hGlobal;
#endif
LPNETRESOURCE pnr = (LPNETRESOURCE)LocalAlloc(LPTR, 1024);
if (pnr)
{
char szBuf[512];
UINT cItems = DropExt_GetNetResource(hnres, (UINT)-1, NULL, 0);
// Get the NETRESOURCE of the first item
DropExt_GetNetResource(hnres, 0, pnr, 1024);
wsprintf(szBuf,
"%d network resource objects in HNRES\n"
"The attributes of the first object are\n"
"\tProvider = %s\n"
"\tRemoteName = %s\n"
"\tdwDisplayType = %x\n"
"\tdwType = %x\n"
"\tdwUsage = %x\n",
cItems,
pnr->lpProvider,
pnr->lpRemoteName ? pnr->lpRemoteName : "N/A",
pnr->dwDisplayType,
pnr->dwType,
pnr->dwUsage);
MessageBox(hwnd, szBuf, "DropExt", MB_OK);
LocalFree(pnr);
}
else
{
hres = ResultFromScode(E_OUTOFMEMORY);
}
//
// HACK: We are supposed to call ReleaseStgMedium. This is a temporary
// hack until OLE 2.01 for Windows 95 is released.
//
if (medium.pUnkForRelease)
{
medium.pUnkForRelease->lpVtbl->Release(medium.pUnkForRelease);
}
else
{
// STGMEDIUM uses anonymous unions, which are not supported in C.
// The code below is conditionalized to show you how the usage differs
// between C and C++.
#if defined (__cplusplus)
GlobalFree(medium.hGlobal);
#else
GlobalFree(medium.u.hGlobal);
#endif
}
}
else
{
MessageBox(hwnd, "No network objects in the selection", "DropExt", MB_OK);
}
return hres;
}
STDMETHODIMP DropExt_InvokeCommand(LPCONTEXTMENU pctm,
LPCMINVOKECOMMANDINFO lpici)
{
PSAMPLEDROPEXT this = PCTM2PSMX(pctm);
HRESULT hres = ResultFromScode(E_INVALIDARG); // assume error
//
// No need to support string based command.
//
if (!HIWORD(lpici->lpVerb))
{
UINT idCmd = LOWORD(lpici->lpVerb);
switch(idCmd)
{
case 0:
hres = DropExt_CheckForHDROP(this, lpici->hwnd);
break;
case 1:
hres = DropExt_CheckForHNRES(this, lpici->hwnd);
break;
}
}
return hres;
}
#pragma argsused
STDMETHODIMP DropExt_GetCommandString(
LPCONTEXTMENU pctm,
UINT idCmd,
UINT wReserved,
UINT FAR * pwReserved,
LPSTR pszName,
UINT cchMax)
{
return NOERROR;
}
//---------------------------------------------------------------------------
// CSampleDropExt::AddRef (IContextMenu override)
//---------------------------------------------------------------------------
STDMETHODIMP_(UINT) DropExt_CTM_AddRef(LPCONTEXTMENU pctm)
{
PSAMPLEDROPEXT this = PCTM2PSMX(pctm);
return ++this->_cRef;
}
//---------------------------------------------------------------------------
// CSampleDropExt::AddRef (IShellExtInit override)
//---------------------------------------------------------------------------
STDMETHODIMP_(UINT) DropExt_SXI_AddRef(LPSHELLEXTINIT psxi)
{
PSAMPLEDROPEXT this = PSXI2PSMX(psxi);
return ++this->_cRef;
}
//---------------------------------------------------------------------------
// CSampleDropExt::Release (IContextMenu override)
//---------------------------------------------------------------------------
STDMETHODIMP_(UINT) DropExt_CTM_Release(LPCONTEXTMENU pctm)
{
PSAMPLEDROPEXT this = PCTM2PSMX(pctm);
if (--this->_cRef) {
return this->_cRef;
}
if (this->_pdtobj) {
this->_pdtobj->lpVtbl->Release(this->_pdtobj);
}
if (this->_hkeyProgID) {
RegCloseKey(this->_hkeyProgID);
}
LocalFree((HLOCAL)this);
g_cRefThisDll--;
return 0;
}
//---------------------------------------------------------------------------
// CSampleDropExt::Release (IShellExtInit thunk)
//---------------------------------------------------------------------------
STDMETHODIMP_(UINT) DropExt_SXI_Release(LPSHELLEXTINIT psxi)
{
PSAMPLEDROPEXT this = PSXI2PSMX(psxi);
return DropExt_CTM_Release(&this->_ctm);
}
//---------------------------------------------------------------------------
// CSampleDropExt::QueryInterface (IContextMenu override)
//---------------------------------------------------------------------------
STDMETHODIMP DropExt_CTM_QueryInterface(LPCONTEXTMENU pctm, REFIID riid, LPVOID FAR* ppvOut)
{
PSAMPLEDROPEXT this = PCTM2PSMX(pctm);
if (IsEqualIID(riid, &IID_IContextMenu) || IsEqualIID(riid, &IID_IUnknown))
{
(LPCONTEXTMENU)*ppvOut=pctm;
this->_cRef++;
return NOERROR;
}
if (IsEqualIID(riid, &IID_IShellExtInit))
{
(LPSHELLEXTINIT)*ppvOut=&this->_sxi;
this->_cRef++;
return NOERROR;
}
return ResultFromScode(E_NOINTERFACE);
}
//---------------------------------------------------------------------------
// CSampleDropExt::QueryInterface (IShellExtInit thunk)
//---------------------------------------------------------------------------
STDMETHODIMP DropExt_SXI_QueryInterface(LPSHELLEXTINIT psxi, REFIID riid, LPVOID FAR* ppv)
{
PSAMPLEDROPEXT this = PSXI2PSMX(psxi);
return DropExt_CTM_QueryInterface(&this->_ctm, riid, ppv);
}
//---------------------------------------------------------------------------
// CSampleDropExt class : Vtables
//---------------------------------------------------------------------------
#pragma data_seg(".text")
#pragma warn -sus
IContextMenuVtbl c_SampleDropExt_CTMVtbl = {
DropExt_CTM_QueryInterface,
DropExt_CTM_AddRef,
DropExt_CTM_Release,
DropExt_QueryContextMenu,
DropExt_InvokeCommand,
DropExt_GetCommandString,
};
IShellExtInitVtbl c_SampleDropExt_SXIVtbl = {
DropExt_SXI_QueryInterface,
DropExt_SXI_AddRef,
DropExt_SXI_Release,
DropExt_Initialize
};
#pragma warn .sus
#pragma data_seg()